package com.asa.tongji.fenxi;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;

import com.asa.hutils.MathHUtils;
import com.asa.tongji.TUtils1;
import com.asa.tongji.bean.YinZiFenXiBaoGao;
import com.asa.utils.Calculate;
/**
 * 全部搞定了，剩下的工作室修改方法，使其通用化，和方法化
 * 求解旋转后的因子载荷量，是真的要优化一下更好，是用我自己的一些判断做出来的
 * 因子分析，因子数量可以由人为经验来判断的，也可以根据特征值来判断（特征值得权重），
 * @author Administrator
 *
 */
public class YinZiFenXi {
	
	public static void main(String[] args) throws Exception {
		double[][] yuanshuju = new double[15][6];
		double[][] yuanshuju2 = new double[6][15];
		yuanshuju[0][0] = 5;
		yuanshuju[0][1] = 5;
		yuanshuju[0][2] = 5;
		yuanshuju[0][3] = 4;
		yuanshuju[0][4] = 4;
		yuanshuju[0][5] = 2;
		
		yuanshuju[1][0] = 5;
		yuanshuju[1][1] = 4;
		yuanshuju[1][2] = 5;
		yuanshuju[1][3] = 2;
		yuanshuju[1][4] = 2;
		yuanshuju[1][5] = 2;
		
		yuanshuju[2][0] = 4;
		yuanshuju[2][1] = 4;
		yuanshuju[2][2] = 4;
		yuanshuju[2][3] = 4;
		yuanshuju[2][4] = 4;
		yuanshuju[2][5] = 4;
		
		yuanshuju[3][0] = 2;
		yuanshuju[3][1] = 3;
		yuanshuju[3][2] = 4;
		yuanshuju[3][3] = 3;
		yuanshuju[3][4] = 3;
		yuanshuju[3][5] = 3;
		
		yuanshuju[4][0] = 3;
		yuanshuju[4][1] = 3;
		yuanshuju[4][2] = 3;
		yuanshuju[4][3] = 3;
		yuanshuju[4][4] = 4;
		yuanshuju[4][5] = 1;
		
		yuanshuju[5][0] = 5;
		yuanshuju[5][1] = 4;
		yuanshuju[5][2] = 5;
		yuanshuju[5][3] = 3;
		yuanshuju[5][4] = 2;
		yuanshuju[5][5] = 3;
		
		yuanshuju[6][0] = 5;
		yuanshuju[6][1] = 5;
		yuanshuju[6][2] = 5;
		yuanshuju[6][3] = 4;
		yuanshuju[6][4] = 5;
		yuanshuju[6][5] = 5;
		
		yuanshuju[7][0] = 3;
		yuanshuju[7][1] = 1;
		yuanshuju[7][2] = 2;
		yuanshuju[7][3] = 5;
		yuanshuju[7][4] = 4;
		yuanshuju[7][5] = 4;
		
		yuanshuju[8][0] = 4;
		yuanshuju[8][1] = 1;
		yuanshuju[8][2] = 3;
		yuanshuju[8][3] = 3;
		yuanshuju[8][4] = 2;
		yuanshuju[8][5] = 3;
		
		yuanshuju[9][0] = 1;
		yuanshuju[9][1] = 2;
		yuanshuju[9][2] = 2;
		yuanshuju[9][3] = 2;
		yuanshuju[9][4] = 2;
		yuanshuju[9][5] = 2;
		
		yuanshuju[10][0] = 3;
		yuanshuju[10][1] = 2;
		yuanshuju[10][2] = 3;
		yuanshuju[10][3] = 1;
		yuanshuju[10][4] = 1;
		yuanshuju[10][5] = 1;
		
		yuanshuju[11][0] = 4;
		yuanshuju[11][1] = 3;
		yuanshuju[11][2] = 4;
		yuanshuju[11][3] = 4;
		yuanshuju[11][4] = 3;
		yuanshuju[11][5] = 4;
		
		yuanshuju[12][0] = 3;
		yuanshuju[12][1] = 2;
		yuanshuju[12][2] = 3;
		yuanshuju[12][3] = 4;
		yuanshuju[12][4] = 5;
		yuanshuju[12][5] = 5;
		
		yuanshuju[13][0] = 4;
		yuanshuju[13][1] = 3;
		yuanshuju[13][2] = 4;
		yuanshuju[13][3] = 5;
		yuanshuju[13][4] = 4;
		yuanshuju[13][5] = 5;
		
		yuanshuju[14][0] = 2;
		yuanshuju[14][1] = 2;
		yuanshuju[14][2] = 3;
		yuanshuju[14][3] = 5;
		yuanshuju[14][4] = 5;
		yuanshuju[14][5] = 4;
		for (int i = 0; i < yuanshuju.length; i++) {
			for (int j = 0; j < yuanshuju[i].length; j++) {
				yuanshuju2[j][i] = yuanshuju[i][j];
			}
		}
		//这里是认为假设有几种元素导致缘由,例子中时两种元素
		//System.out.println("....................main........................");
		stepA(yuanshuju2);
		
		
	}
	
	/**
	 * 标准值化
	 */
	private static double[][] biaozhunzhihua(double[][] x){
		double[] averages = new double[x.length];
		for (int i = 0; i < averages.length; i++) {
			averages[i] = TUtils1.average(x[i]);
		}
		double[] variances = new double[x.length];
		for (int i = 0; i < variances.length; i++) {
			variances[i] = TUtils1.standardDeviation_chafen(x[i]);
		}
		double[][] xu = new double[x.length][x[0].length];
		for (int i = 0; i < xu.length; i++) {
			for (int j = 0; j < xu[i].length; j++) {
				xu[i][j] = (x[i][j]-averages[i])/variances[i];
			}
		}
		return xu;
	}
	/**
	 * 标准值化2
	 * @throws Exception 
	 */
	private static double[][] biaozhunzhihua2(double[][] xu,double[][] x) throws Exception{
		int xiangguanxishu[][] = cixu(x.length);
		for (int i = 0; i < xiangguanxishu.length; i++) {
			//System.out.println(Arrays.toString(xiangguanxishu[i]));
		}
		double asa[] = new double[xiangguanxishu.length];
		for (int i = 0; i < xiangguanxishu.length; i++) {
			asa[i] = TUtils1.correlationCoefficient(xu[xiangguanxishu[i][0]], xu[xiangguanxishu[i][1]]);
		}
		
		//System.out.println(Arrays.toString(asa));
		double[][] A = new double[x.length][x.length];
		for (int i = 0; i < A.length; i++) {
			A[i][i] = 1;
		}
		for (int i = 0; i < xiangguanxishu.length; i++) {
			BigDecimal bd = new BigDecimal(asa[i]);  
	        bd = bd.setScale(2, RoundingMode.HALF_UP);
			A[xiangguanxishu[i][0]][xiangguanxishu[i][1]] = Double.parseDouble(bd.toString());
			A[xiangguanxishu[i][1]][xiangguanxishu[i][0]] = Double.parseDouble(bd.toString());
		}
		return A;
	}
	
	
	
	private static YinZiFenXiBaoGao stepA(double[][] x) throws Exception{
		
		double[][] xu = biaozhunzhihua(x);
		for (int i = 0; i < xu.length; i++) {
			for (int j = 0; j < xu[i].length; j++) {
				System.out.print(xu[i][j]+"\t");
			}
			//System.out.println();
		}
		
		double[][] A = biaozhunzhihua2(xu, x);
		for (int i = 0; i < A.length; i++) {
			for (int j = 0; j < A[i].length; j++) {
				System.out.print(A[i][j]+"\t");
			}
			//System.out.println();
		}
		double[] juzhengtezhengzhi = MathHUtils.juzhengtezhengzhi(A);
		double[][] juzhengtezhengxiangliang = MathHUtils.juzhengtezhengxiangliang(A);
		//System.out.println("==============特征向量=================");
		double sumjuzhengtezhengzhi = 0;
		for (int i = 0; i < juzhengtezhengxiangliang.length; i++) {
			System.out.print(juzhengtezhengzhi[i]+"\t");
			sumjuzhengtezhengzhi += Math.abs(juzhengtezhengzhi[i]);
		}
		//System.out.println();
		int yinsu_nn=0;
		for (yinsu_nn = 0; yinsu_nn < juzhengtezhengxiangliang.length; yinsu_nn++) {
			if (juzhengtezhengzhi[yinsu_nn]/sumjuzhengtezhengzhi<1.0/(double)sumjuzhengtezhengzhi) {
				break;
			}
		}

		
		for (int i = 0; i < juzhengtezhengxiangliang.length; i++) {
			for (int j = 0; j < juzhengtezhengxiangliang.length; j++) {
				System.out.print(juzhengtezhengxiangliang[i][j]+"\t");
			}
			//System.out.println();
		}
		
		
		//System.out.println("*************特征向量输出完毕********************");

		double[][] chushi = new double[yinsu_nn][juzhengtezhengxiangliang.length];
		//System.out.println("=====================================================================================");
		for (int i = 0; i < chushi.length; i++) {
			for (int j = 0; j < chushi[i].length; j++) {
				
				chushi[i][j] = Math.sqrt(juzhengtezhengzhi[i])*juzhengtezhengxiangliang[i][j];
				System.out.print(chushi[i][j]+"  。。。 ");
			}
			//System.out.println();
		}
		for (int i = 0; i < A.length; i++) {
			A[i][i] = chushi[0][i]*chushi[0][i]+chushi[1][i]*chushi[1][i];
		}
		for (int i = 0; i < A.length; i++) {
			for (int j = 0; j < A[i].length; j++) {
				System.out.print(A[i][j]+"\t");
			}
			//System.out.println();
		}
		juzhengtezhengzhi = MathHUtils.juzhengtezhengzhi(A);
		juzhengtezhengxiangliang = MathHUtils.juzhengtezhengxiangliang(A);
		//System.out.println("==============特征向量=================");
		//System.out.println(juzhengtezhengzhi[0]+"\t"+juzhengtezhengzhi[1]+"\t"+juzhengtezhengzhi[2]);
		
		for (int i = 0; i < juzhengtezhengxiangliang.length; i++) {
			for (int j = 0; j < juzhengtezhengxiangliang.length; j++) {
				System.out.print(juzhengtezhengxiangliang[i][j]+"\t");
			}
			//System.out.println();
		}
		
		
		
		for (int i = 0; i < chushi.length; i++) {
			for (int j = 0; j < chushi[i].length; j++) {
				
				chushi[i][j] = Math.sqrt(juzhengtezhengzhi[i])*juzhengtezhengxiangliang[i][j];
				System.out.print(chushi[i][j]+"  。。。 ");
			}
			//System.out.println();
		}
		for (int i = 0; i < A.length; i++) {
			A[i][i] = chushi[0][i]*chushi[0][i]+chushi[1][i]*chushi[1][i];
		}
		for (int i = 0; i < A.length; i++) {
			for (int j = 0; j < A[i].length; j++) {
				System.out.print(A[i][j]+"\t");
			}
			//System.out.println();
		}
		juzhengtezhengzhi = MathHUtils.juzhengtezhengzhi(A);
		juzhengtezhengxiangliang = MathHUtils.juzhengtezhengxiangliang(A);
		//System.out.println("==============特征向量=================");
		//System.out.println(juzhengtezhengzhi[0]+"\t"+juzhengtezhengzhi[1]+"\t"+juzhengtezhengzhi[2]);
		
		for (int i = 0; i < juzhengtezhengxiangliang.length; i++) {
			for (int j = 0; j < juzhengtezhengxiangliang.length; j++) {
				System.out.print(juzhengtezhengxiangliang[i][j]+"\t");
			}
			//System.out.println();
		}
		
		//System.out.println("=====================================================================================");
		a:while (true) {
			
			/**
			 * 先写死，只考虑两种因素分析的情况
			 */
			
			for (int i = 0; i < chushi.length; i++) {
				for (int j = 0; j < chushi[i].length; j++) {
					
					chushi[i][j] = Math.sqrt(juzhengtezhengzhi[i])*juzhengtezhengxiangliang[i][j];
					System.out.print(chushi[i][j]+"  。。。 ");
				}
				//System.out.println();
			}
			//System.out.println("============矩阵乘法=================");
			double[][] zhuanzhi = MathHUtils.zhuanzhi(chushi);
			
			
			double[][] chenfa = MathHUtils.chenfa(zhuanzhi, chushi);
			for (int i = 0; i < chenfa.length; i++) {
				for (int j = 0; j < chenfa[i].length; j++) {
					System.out.print(chenfa[i][j]+"   ");
				}
				//System.out.println();
				
			}
			for (int i = 0; i < chenfa.length; i++) {
				A[i][i] = chenfa[i][i];
			}
			juzhengtezhengzhi = MathHUtils.juzhengtezhengzhi(A);
			juzhengtezhengxiangliang = MathHUtils.juzhengtezhengxiangliang(A);
			//System.out.println("==============特征向量=================");
			//System.out.println(juzhengtezhengzhi[0]+"\t"+juzhengtezhengzhi[1]+"\t"+juzhengtezhengzhi[2]);
			
			for (int i = 0; i < juzhengtezhengxiangliang.length; i++) {
				for (int j = 0; j < juzhengtezhengxiangliang.length; j++) {
					System.out.print(juzhengtezhengxiangliang[i][j]+"\t");
				}
				//System.out.println();
			}
			
			//System.out.println("*************特征向量输出完毕====================");
			
			for (int j = 0; j < A.length; j++) {
				 if (A[j][j]>1) {
					break;
				}
				if (j == A.length-1) {
					break a;
				}
			}
			
		}
		
		for (int i = 0; i < chushi.length; i++) {
			for (int j = 0; j < chushi[i].length; j++) {
				chushi[i][j] = Math.sqrt(juzhengtezhengzhi[i])*juzhengtezhengxiangliang[i][j];
				System.out.print(chushi[i][j]+"   ");
			}
			//System.out.println();
		}
		//System.out.println("==========================================");
		for (int i = 0; i < chushi.length; i++) {
			for (int j = 0; j < chushi.length; j++) {
				if (chushi[i][j]<0&&j!=0) {
					for (int k = 0; k < chushi.length; k++) {
						chushi[i][k] = -chushi[i][j];
					}
					break;
				}
			}
		}
		for (int i = 0; i < chushi.length; i++) {
			for (int j = 0; j < chushi[i].length; j++) {
				System.out.print(chushi[i][j]+" chushi  ");
			}
			//System.out.println();
		}
		
		double[][] varrimax = varimax(chushi);
		for (int i = 0; i < varrimax.length; i++) {
			for (int j = 0; j < varrimax[i].length; j++) {
				System.out.print(varrimax[i][j]+"   ");
			}
			//System.out.println();
		}
		
		
		//System.out.println("==========================================");
		/**
		 * 还可以继续完备这个结果
		 * 1，求解旋转后的因子载荷量
		 * 2，误差分析
		 * 3，求出因子得分，充分理解每个个体的特征（这里使用的是回归法）
		 */
		//System.out.println("矩阵的最终变换");
		for (int i = 0; i < A.length; i++) {
			for (int j = 0; j < A[i].length; j++) {
				System.out.print(A[i][j]+"   ");
			}
			//System.out.println();
		}
		//System.out.println("误差分析");
		double sum = 0;
		double times = varrimax.length;
		for (int i = 0; i < varrimax.length; i++) {
			for (int j = 0; j < varrimax[i].length; j++) {
				sum=sum +varrimax[i][j]*varrimax[i][j];
			}
		}
		//System.out.println(sum/times);//这个误差分析是错误的，还要去找资料，书上的写得太诡异了，一般要求这个值大于50%
		//System.out.println("============danyinzi===============");
		
		double[][] danyinzi = danyinzi(x, varrimax);
		
		//System.out.println("转后的因子载荷量数据点：");
		for (int i = 0; i < varrimax.length; i++) {
			for (int j = 0; j < varrimax[i].length; j++) {
				System.out.print(varrimax[i][j]+"             ");
			}
			//System.out.println();
		}
		
		//System.out.println("误差分析"+sum/times);
		//System.out.println("对于样本的，每个单因子，权重计算");
		for (int i = 0; i < danyinzi.length; i++) {
			for (int j = 0; j < danyinzi[i].length; j++) {
				System.out.print(danyinzi[i][j]+"             ");
			}
			//System.out.println();
		}
		
		YinZiFenXiBaoGao baoGao = new YinZiFenXiBaoGao();
		baoGao.setAa(chushi);
		baoGao.setRaa(varrimax);
		baoGao.setWuchafenxi(sum/times);
		baoGao.setYinzidefen(danyinzi);
		baoGao.setTezhengzhi(juzhengtezhengzhi);
		return baoGao;
	}
	
	/**
	 * 求解旋转后的因子载荷量
	 * 这种方法是我自己用脑洞整出来的，还需各种情况的测试
	 * @param x
	 * @return
	 */
	private static double[][] varimax(double[][] a){
//		System.out.println();
//		System.out.println("asa asa asa asa :"+a.length + " asa "+ a[0].length);
		a = MathHUtils.zhuanzhi(a);
//		System.out.println("asa asa asa asa :"+a.length + " asa "+ a[0].length);

		double sum = 0;
		int n = 0;
		for (int i = 0; i < a.length; i++) {
			double x = a[i][0]/a[i][1];
			//System.out.println(x);
			if (x<1&&x>-1) {
				sum += x;
				n++;
			}
		}
		double asin = Math.asin(sum/n);
		asin = 90-asin*180/Math.PI;
		double sin = Math.sin(asin*Math.PI/180);
		double cos = Math.cos(asin*Math.PI/180);
		//System.out.println(asin+"..........................");
		//System.out.println("===================");
		//System.out.println("再输出的特别的看看吧");
		for (int i = 0; i < a.length; i++) {
			//System.out.println(a[i][1]/a[i][0]);
		}
		//System.out.println("===================");
		
		
		
		//System.out.println("sin    "+sin);
		//System.out.println("cos    "+cos);
		double[][] b = {{cos,sin},{-sin,cos}};
		double[][] chenfa = MathHUtils.chenfa(a, b);
		 for (int i = 0; i < chenfa.length; i++) {
			for (int j = 0; j < chenfa[i].length; j++) {
				System.out.print(chenfa[i][j]+"   ");
			}
			//System.out.println();
		}
		
		return chenfa;
	}
	
	/**
	 * 3，求出因子得分，充分理解每个个体的特征（这里使用的是回归法）
	 * @param x
	 * @param z
	 * @return
	 * @throws Exception
	 */
	private static double[][] danyinzi(double[][] x,double[][] z) throws Exception{
		double[] averages = new double[x.length];
		for (int i = 0; i < averages.length; i++) {
			averages[i] = TUtils1.average(x[i]);
		}
		double[] variances = new double[x.length];
		for (int i = 0; i < variances.length; i++) {
			variances[i] = TUtils1.standardDeviation_chafen(x[i]);
		}
		double[][] xu = new double[x.length][x[0].length];
		for (int i = 0; i < xu.length; i++) {
			for (int j = 0; j < xu[i].length; j++) {
				xu[i][j] = (x[i][j]-averages[i])/variances[i];
			}
		}
		for (int i = 0; i < xu.length; i++) {
			for (int j = 0; j < xu[i].length; j++) {
				System.out.print(xu[i][j]+"\t");
			}
			//System.out.println();
		}
		
		
		int xiangguanxishu[][] = cixu(x.length);
		for (int i = 0; i < xiangguanxishu.length; i++) {
			//System.out.println(Arrays.toString(xiangguanxishu[i]));
		}
		double asa[] = new double[xiangguanxishu.length];
		for (int i = 0; i < xiangguanxishu.length; i++) {
			asa[i] = TUtils1.correlationCoefficient(xu[xiangguanxishu[i][0]], xu[xiangguanxishu[i][1]]);
		}
		
		//System.out.println(Arrays.toString(asa));
		double[][] A = new double[x.length][x.length];
		for (int i = 0; i < A.length; i++) {
			A[i][i] = 1;
		}
		for (int i = 0; i < xiangguanxishu.length; i++) {
			BigDecimal bd = new BigDecimal(asa[i]);  
	        bd = bd.setScale(2, RoundingMode.HALF_UP);
			A[xiangguanxishu[i][0]][xiangguanxishu[i][1]] = Double.parseDouble(bd.toString());
			A[xiangguanxishu[i][1]][xiangguanxishu[i][0]] = Double.parseDouble(bd.toString());
		}
		
		for (int i = 0; i < A.length; i++) {
			for (int j = 0; j < A[i].length; j++) {
				System.out.print(A[i][j]+"\t");
			}
			//System.out.println();
		}
		
		xu = MathHUtils.zhuanzhi(xu);
		A = MathHUtils.juzhengni(A);
		z = MathHUtils.chenfa(A, z);
		z = MathHUtils.chenfa(xu, z);
		//System.out.println("................................");
		for (int i = 0; i < z.length; i++) {
			for (int j = 0; j < z[i].length; j++) {
				System.out.print(z[i][j]+"   ");
			}
			//System.out.println();
		}
		//System.out.println("................................");
		
		return z;
	}
	
	
	private static int[][] cixu(int x){
		int zuhe = (int)Calculate.zuhe(x, 2);//计算有多少种组合方式
		//System.out.println(zuhe);
		int[][] asa = new int[zuhe][2]; 
		int k = 0;
		for (int i = 0; i < x-1; i++) {
			for (int j = i+1; j < x; j++) {
				asa[k][0] = i;
				asa[k][1] = j;
				k++;
			}
		}
		return asa;
	}
	
	
}
